#include "stdafx.h"
#include "GroundTrafficController.h"
#include "GateStand.h"
#include "LongTermStand.h"
#include "Aircraft.h"
#include "AirportManager.h"
#include "Time.h"

#include <iostream>

using namespace std;

const string GROUND = "GROUND";
const string AIR = "AIR";
const string AVAILABLE = "AVAILABLE";

int err = 1;

/*------------------------------------------------------------
/ GroundTrafficController
/ Description: Default constructor 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
GroundTrafficController::GroundTrafficController(void) : Employee (){

	longTermStandList = new std::list<LongTermStand>();
	gateStandList = new std::list<GateStand>();
	unassignedFlightList = new std::list<Flight>();
}

/*------------------------------------------------------------
/ GroundTrafficController
/ Description: Default constructor 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
GroundTrafficController::GroundTrafficController(string empID, string empPassword) : Employee (empID, empPassword)
{
	longTermStandList = new std::list<LongTermStand>();
	gateStandList = new std::list<GateStand>();
	unassignedFlightList = new std::list<Flight>();
}

/*------------------------------------------------------------
/ ~GroundTrafficController
/ Description: Default destructor
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
GroundTrafficController::~GroundTrafficController(){
}


/*------------------------------------------------------------
/ overlaps
/ Description: a helper method used to help flight allocations determine whether a gate is free during a particular interval
/ Parameters: takes two time intervals, one from a flight, and one from a gate
/ Return: returns 1 if an overlap between time interval A and time interval B is detected
		  returns 0 if the times are determined to have no overlap

------------------------------------------------------------*/
int overlaps(Time* A_in, Time* A_out, Time* B_in, Time* B_out){
	//return one if a legitimate overlap exists and there is interference from one flight on an other
	if(((B_in < A_out)&&(B_out > A_in))||((B_in < A_out)&&(B_out > A_in))){
		return 1;
	}

	//return 0 if no overlap exists between flightss
	return 0;
}


/*------------------------------------------------------------
/ allocateGateStandIncoming
/ Description: 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
int GroundTrafficController::allocateGateStandIncoming(GateStand* _newGateStand, Flight* _newFlight){
		
	std::list<GateStand>::iterator it; // iterator for gate stand list
	std::list<Flight>::iterator it2; //iterator for flight list in gate stand
	std::list<Flight>::iterator it3; //iterator for the unassigned flight list
	std::list<Flight>::iterator it4; //used to look for time conflicts with arriving flights
	int standFlag = 0, flightFlag = 0, foundGoodStand = 0;
	Time *newFlightTime; 
	
	
	newFlightTime = _newFlight->getArrivalTime();

	if(err++)std::cout<<"allocateGateStandIncoming "<<err<<"\n";system("PAUSE");
	//if the list is empty, error
	if (gateStandList->empty()){
		return 0;
	}
	
	if(err++)std::cout<<"allocateGateStandIncoming "<<err<<"\n";system("PAUSE");
	
	//if the lists are not empty, search for proper location
	it = gateStandList->begin();
	it2 = unassignedFlightList->begin();

	if(err++)std::cout<<"allocateGateStandIncoming "<<err<<"\n";system("PAUSE");
	
	//find the position for the stand object in the list
	while (!standFlag && it != gateStandList->end()){
		if (it->getStandID() == _newGateStand->getStandID()){
				standFlag = 1; //found stand
		}else{
			it++;
		}
	}

	//the stand doesn't exist, exit function
	if(!standFlag){
		return 0;
	}


	//find the position for the flight object in the list
	while (!flightFlag && it2 !=  unassignedFlightList->end()){
		if (it2->getFlightID() == _newFlight->getFlightID()){
				flightFlag = 1; //found flight
		}else{
			it2++;
		}
	}

	//the flight is already assigned, or doesn't exist, exit function
	if(!flightFlag){
		return 0;
	}


	//prepare to search for gate availability times
	it3 = it->getAccomodationList()->begin();
	standFlag = 0;

	//check that the incoming flight does not occupy any interval allocated to another flight that exists in the this gatestand list
	//if it does return 0
	//otherwise continue
	//dereference it to get the gatestand it's landing at
	it4 = it->getAccomodationList()->begin();

	Time* A_in;		//time of arrival for the arriving plane
	Time* A_out;	//earliest time by which the arriving plane wil lbe ready to disengage from the stand
	Time* A_delay;	//delay margin on the arriving plane
	
	Time* B_in;		//time of arrival/departure for a plane stacked up on the current gate
	Time* B_out;	//earliest time by which the arriving/departing plan stacked up on the current gate
	Time* B_delay;	//delay margin on the arriving/departing plane

	
	A_in = _newFlight->getArrivalTime();
	
	Time* temp = new Time(_newFlight->getType()->getBoardingTime());
	A_out = *temp + A_in;
	
	A_delay = _newFlight->getDelayAmount();
	A_in = *A_in + A_delay;
	A_out = *A_out + A_delay;


	while(!foundGoodStand && it4 != it->getAccomodationList()->end()){
		//see if there is an incoming or outgoing flight under it4
		//********************************************************************************************************************
		//IMPORTANT - HINGES ON OUTPUT OF GETSTATUS(), WHICH IS 0 IF SHOULD GET DEPARTURE TIMES, 1 IF SHOULD GET ARRIVAL TIMES
		//********************************************************************************************************************
		if(it4->getStatus() == 1){
			B_in = it4->getArrivalTime();
			B_out = new Time(it4->getType()->getServiceTime());
			B_delay = it4->getDelayAmount();
			B_in = *B_in + B_delay;
			B_out = *B_out + B_delay;
		}
		else if (it4->getStatus() == 0){
			B_in = it4->getDepartureTime();
			B_out = new Time(it4->getType()->getBoardingTime());
			B_delay = it4->getDelayAmount();
			B_in = *B_in + B_delay;
			B_out = *B_out + B_delay;
		}
		//if an open stand is found, set the found flag to true
		if(!overlaps(A_in, A_out, B_in, B_out)){
			foundGoodStand = 1;
		}
		++it4;

	}
	


	//find the position for the flight object in the gate list
	while (!standFlag && it3 != it->accomodationList->end()){
		if(it3->getArrivalTime() == NULL){
			if (newFlightTime < (it3->getDepartureTime()) == 0){	//MARK - CHECK THIS, THE FUNCTIONALITY OF COMPARETIME() IS GONE, REPLACED WITH </> RECHECK	
					standFlag = 1; //found position
			}else{
				it3++;
			}
		}
	}

	//add the flight to the allocation stand of the associated gate  //ADD SAME CODE TO OUTGOING FLIGHT
	if (it3 == it->getAccomodationList()->end()){
		if (newFlightTime < it3->getDepartureTime()){
			it->getAccomodationList()->push_back(*_newFlight);
		}else{
			it->getAccomodationList()->insert(it3,*_newFlight);
		}
	}else{
		it->getAccomodationList()->insert(it3,*_newFlight);
	}

	
	//remove the flight from unassigned flights
	unassignedFlightList->erase(it3);

    return 1;
}

/*------------------------------------------------------------
/ allocateGateStandOutgoing
/ Description: 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
int GroundTrafficController::allocateGateStandOutgoing(GateStand* _newGateStand, Flight* _newFlight){

	std::list<GateStand>::iterator it; // iterator for gate stand list
	std::list<Flight>::iterator it2; //iterator for flight list in gate stand
	std::list<Flight>::iterator it3; //iterator for the unassigned flight list
	std::list<Flight>::iterator it4; //used to look for time conflicts with departing flights
	int standFlag = 0, flightFlag = 0, foundGoodStand = 0;
	Time *newFlightTime;
	
	//get the flight time for comparison
	if (_newFlight->getArrivalTime() == NULL){
		newFlightTime = _newFlight->getDepartureTime();
	}else{
		newFlightTime = _newFlight->getArrivalTime();
	}

	//if the list is empty, error
	if (gateStandList->empty()){
		return -1;
	}

	//if the lists are not empty, search for proper location
	it = gateStandList->begin();
	it2 = unassignedFlightList->begin();

	//find the position for the stand object in the list
	while (!standFlag && it != gateStandList->end()){
		if (it->getStandID() == _newGateStand->getStandID()){
				standFlag = 1; //found stand
		}else{
			it++;
		}
	}

	//the stand doesn't exist, exit function
	if(!standFlag){
		return 0;
	}

	//find the position for the flight object in the list
	while (!flightFlag && it2 !=  unassignedFlightList->end()){
		if (it2->getFlightID() == _newFlight->getFlightID()){
				flightFlag = 1; //found flight
		}else{
			it2++;
		}
	}

	//set up for 3rd iteration
	it3 = it->accomodationList->begin();
	standFlag = 0;

	//check that the incoming flight does not occupy any interval allocated to another flight that exists in the this gatestand list
	//if it does return 0
	//otherwise continue
	//dereference it to get the gatestand it's landing at
	it4 = it->accomodationList->begin();

	Time* A_in;		//time of arrival for the arriving plane
	Time* A_out;	//earliest time by which the arriving plane wil lbe ready to disengage from the stand
	Time* A_delay;	//delay margin on the arriving plane
	
	Time* B_in;		//time of arrival/departure for a plane stacked up on the current gate
	Time* B_out;	//earliest time by which the arriving/departing plan stacked up on the current gate
	Time* B_delay;	//delay margin on the arriving/departing plane

	
	A_in = _newFlight->getArrivalTime();
	
	Time* temp = new Time(_newFlight->getType()->getBoardingTime());
	A_out = *temp + A_in;
	
	A_delay = _newFlight->getDelayAmount();
	A_in = *A_in + A_delay;
	A_out = *A_out + A_delay;


	while(!foundGoodStand && it4 != it->accomodationList->end()){
		//see if there is an incoming or outgoing flight under it4
		//********************************************************************************************************************
		//IMPORTANT - HINGES ON OUTPUT OF GETSTATUS(), WHICH IS 0 IF SHOULD GET DEPARTURE TIMES, 1 IF SHOULD GET ARRIVAL TIMES
		//********************************************************************************************************************
		if(it4->getStatus() == 1){
			B_in = it4->getArrivalTime();
			B_out = new Time(it4->getType()->getServiceTime());
			B_delay = it4->getDelayAmount();
			B_in = *B_in + B_delay;
			B_out = *B_out + B_delay;
		}
		else if (it4->getStatus() == 0){
			B_in = it4->getDepartureTime();
			B_out = new Time(it4->getType()->getBoardingTime());
			B_delay = it4->getDelayAmount();
			B_in = *B_in + B_delay;
			B_out = *B_out + B_delay;
		}
		//if an open stand is found, set the found flag to true
		if(!overlaps(A_in, A_out, B_in, B_out)){
			foundGoodStand = 1;
		}
		++it4;

	}
	


	//find the position for the flight object in the gate list
	while (!standFlag && it3 != it->accomodationList->end()){
		if(it3->getArrivalTime() == NULL){
			if (newFlightTime < (it3->getDepartureTime()) == 0){	//MARK - CHECK THIS, THE FUNCTIONALITY OF COMPARETIME() IS GONE, REPLACED WITH </> RECHECK	
					standFlag = 1; //found position
			}else{
				it3++;
			}
		}
	}

	//add the flight to the allocation stand of the associated gate  //ADD SAME CODE TO OUTGOING FLIGHT
	if (it3 == it->getAccomodationList()->end()){
		if (newFlightTime < it3->getArrivalTime()){
			it->getAccomodationList()->push_back(*_newFlight);
		}else{
			it->getAccomodationList()->insert(it3,*_newFlight);
		}
	}else{
		it->getAccomodationList()->insert(it3,*_newFlight);
	}

	//remove the flight from unassigned flights
	unassignedFlightList->erase(it3);

    return 0;
}



/*------------------------------------------------------------
/ reallocateStand
/ Description: 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
int GroundTrafficController::reallocateStand(GateStand *newStand, Aircraft* air){
	//if the stand passed in is free

	//ensure that no reallocation of aircrafts being boarded or serviced
	if(air->getCurrentLocation().compare("AVAILABLE") != 0){
		return 0;
	}
	if (newStand->getCurrentAircraft() == NULL){
		//if the stand passed in can hold the aircraft
		if(air->getCurrentLocation().compare(AVAILABLE) != 0){
			return 0;
		}
		if (air->checkStandCompatibility(newStand) == 1){

			//determine if stand is a GateStand or LongTermsStand using "G" ID format rule
			//depending on which, iterate through gateStandList or longTermStandList
			//then get the stand that has the same ID as the one held by *air
			//set that stand's current aicraft  to NULL

			string oldStandID = air->getCurrentStand()->getStandID();
			int foundStand = 0;
			if (oldStandID.at(0) == 'G'){
				//find, set to null
				std::list<GateStand>::iterator it; // iterator for gate stand list

				it = gateStandList->begin();
				while (!foundStand && it !=gateStandList->end()){
					if(it->getStandID().compare(oldStandID) == 0){
						foundStand = 1;
					}
					++it;
				}
				
				--it;
				it->setStandEmpty();
				it->setCurrentAircraft(NULL);

			}else{
				//find, set to null
				std::list<LongTermStand>::iterator it; //iterator for flight list in gate stand
				it = longTermStandList->begin();
				while (!foundStand && it != longTermStandList->end()){
					if(it->getStandID().compare(oldStandID) == 0){
						foundStand = 1;
					}
					++it;
				}

				--it;
				it->setStandEmpty();
				it->setCurrentAircraft(NULL);
			}


			Stand *temp = air->getCurrentStand();	//get the current auircraft stand
			//temp->setStandEmpty();				//set the current stand to empty
			//stand->setStandOccupied();			//set the new stand to full
			air->setCurrentStand(newStand);			//save the new stand to the current location of the aircraft
			newStand->setCurrentAircraft(air);
			return 1; //successful
		}else{
			return 0; //stand type incompatible
		}
	}else{
		return 0; //stand already occupied
	}
}


/*------------------------------------------------------------
/ reallocateStand
/ Description: 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
int GroundTrafficController::reallocateStand(LongTermStand *newStand, Aircraft* air){
	//if the stand passed in is free
	//ensure that no reallocation of aircrafts being boarded or serviced
	if(air->getCurrentLocation().compare("AVAILABLE") != 0){
		return 0;
	}	
	if (newStand->getCurrentAircraft() == NULL){
		//if the stand passed in can hold the aircraft
		if(air->getCurrentLocation().compare(AVAILABLE) != 0){
			return 0;
		}
		if (air->checkStandCompatibility(newStand) == 1){

			
			//determine if stand is a GateStand or LongTermsStand using "G" or "L"
			//depending on which, iterate through gateStandList or longTermStandList
			//then get the stand that has the same ID as the one held by *air
			//set the stand's current aicraft we get from *air to NULL

			string oldStandID = air->getCurrentStand()->getStandID();
			int foundStand = 0;
			if (oldStandID.at(0) == 'G'){
				//find, set to null
				std::list<GateStand>::iterator it; // iterator for gate stand list

				it = gateStandList->begin();
				while (!foundStand && it !=gateStandList->end()){
					if(it->getStandID().compare(oldStandID) == 0){
						foundStand = 1;
					}
					++it;
				}
				
				--it;
				it->setStandEmpty();
				it->setCurrentAircraft(NULL);

			}else{
				//find, set to null
				std::list<LongTermStand>::iterator it; //iterator for flight list in gate stand
				it = longTermStandList->begin();
				while (!foundStand && it != longTermStandList->end()){
					if(it->getStandID().compare(oldStandID) == 0){
						foundStand = 1;
					}
					++it;
				}

				--it;
				it->setStandEmpty();
				it->setCurrentAircraft(NULL);
			}


			Stand *temp = air->getCurrentStand();	//get the current auircraft stand
			//temp->setStandEmpty();				//set the current stand to empty
			//stand->setStandOccupied();			//set the new stand to full
			air->setCurrentStand(newStand);			//save the new stand to the current location of the aircraft
			newStand->setCurrentAircraft(air);
			return 1; //successful
		}else{
			return 0; //stand type incompatible
		}
	}else{
		return 0; //stand already occupied
	}
}

/*------------------------------------------------------------
/ reportDelay
/ Description: 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
void GroundTrafficController::reportDelay(Flight* f, Time* delay){
	std::list<GateStand>::iterator it;
	

	if (f != NULL){
			
		//call increaseDelayAmount for the flight
		//f->increaseDelayAmount(delay);
		
		//check if *f is not the last element in the flight queue for the airport (assumed to be arranged chronologically)
		 //get the flight ID from *f
		//search the gateStandList for *f
		

		
		


		//TAKES IN THE FLIGHT AND DELAY AMOUNT. THEN ADDS THE DELAY
		//TO THE FLIGHT, DELETES THE FLIGHT AT ITS POSITION IN THE LIST
		//THE ADDS IT AT ITS RIGHT LOCATION. AFTER THIS, IT MUST CHECK THAT IT FITS
		//BETWEEN FLIGHT BEFORE AND AFTER IT, OTHERWISE IT INCREASES
		//THE DELAY AMOUNT/DEPARTURE/ARRIVAL TIME... AFTER THIS,
		//IT SEARCHES THROUGH THE LIST OF FLIGHTS FOLLOWING THIS FLIGHT
		//AND CORRECTS THE TIMES ACCORDINGLY, INCASE THEY NOW DO NOT 
		//HAVE ENOUGH ALLOCATION TIME FOR THE FLIGHT TO TAKE PLACE...
		//THIS ITERATION THROUGH THE LIST OF FLIGHTS CONTINUES, UNTIL WE REACH A FLIGHT
		//THAT IS NOT AFFECTED BY THE CHANGE, OR THE NED OF THE LIST
	}

}

/*------------------------------------------------------------
/ createIncomingFlight
/ Description: 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
int GroundTrafficController::createIncomingFlight(string flightId, int aircraftId, Time& arrTime, Time& landTime, string srcAirport){
	
    Time *t = new Time (arrTime);
    Time *t2 = new Time (landTime);
    Time *t3 = new Time (0);
    
	//CREATE THE FLIGHT OBJECT
    Flight *f = new Flight(flightId, aircraftId, t, t2,"", t3, srcAirport, true, NULL);
	
    /*THIS FLIGHT IS CREATED AS AN EMERGENCY, AND DOES NOT NEED TO BE CHECKED WITH THE 
	//AIRPORT MANAGER. HOWEVER, THE FOLLOWING THINGS NEED TO BE ASSURED:
	// 1. THE GATE STAND HAS TO BE FREE AT THE TIME IN ORDER TO BE ALLOCATED
	// 2. THE FLIGHT MUST BE CREATED FURTHER ENOUGH AFTER THE PRECEEDING FLIGHT TO LEAVE ROOM FOR ALLOCATION/DEALLOCATION
	// 3. IF FLIGHTS OCCUR AT THE GATE AFTER THE EMERGENCY FLIGHT, ANY FLIGHTS THAT DO NOT HAVE ENOUGH TIME AVAILABLE FOR
	//		ALLOCATION/DEALLOCATION WILL HAVE TO BE DELAYED ACCORDINGLY
	
    */
	return 0;
}

/*------------------------------------------------------------
/ createOutgoingFlight
/ Description: 
/ Parameters: N/A
/ Return: N/A
------------------------------------------------------------*/
int GroundTrafficController::createOutgoingFlight(string flightId, int aircraftId, Time& departTime, Time& takeOffTime, string destAirport){
	
    Time *t = new Time (departTime);
    Time *t2 = new Time (takeOffTime);
    Time *t3 = new Time (0);
    
  	//CREATE THE FLIGHT OBJECT  
    Flight *f = new Flight(flightId, aircraftId, t, t2, "", t3, destAirport, NULL);
	
	/*THIS FLIGHT IS CREATED AS AN EMERGENCY, AND DOES NOT NEED TO BE CHECKED WITH THE 
	//AIRPORT MANAGER. HOWEVER, THE FOLLOWING THINGS NEED TO BE ASSURED:
	// 1. THE GATE STAND HAS TO BE FREE AT THE TIME IN ORDER TO BE ALLOCATED
	// 2. THE FLIGHT MUST BE CREATED FURTHER ENOUGH AFTER THE PRECEEDING FLIGHT TO LEAVE ROOM FOR ALLOCATION/DEALLOCATION
	// 3. IF FLIGHTS OCCUR AT THE GATE AFTER THE EMERGENCY FLIGHT, ANY FLIGHTS THAT DO NOT HAVE ENOUGH TIME AVAILABLE FOR
	//		ALLOCATION/DEALLOCATION WILL HAVE TO BE DELAYED ACCORDINGLY
	*/
	return 0;
}

/*------------------------------------------------------------
/ getGateStandList
/ Description: returns the stand list
/ Parameters: N/A
/ Return: gate Stand List
------------------------------------------------------------*/
list<GateStand>* GroundTrafficController::getGateStandList (){
	return  gateStandList;
}

/*------------------------------------------------------------
/ getGateLongTermStandList
/ Description: returns the stand list
/ Parameters: N/A
/ Return: Long Term Stand List
------------------------------------------------------------*/
list<LongTermStand>* GroundTrafficController::getLongTermStandList (){
	return  longTermStandList;
}

/*------------------------------------------------------------
/ changePassword
/ By: Trevor Plint
/ Date: March 17 2011
/ Description: deletes a stand by ID  
/ Paramneters: takes a valid ID in string form 
/ Return: 0 if stand cannot be deleted for ligistical reasons
          1 if stand deleted successfully
         0 if stand not found
------------------------------------------------------------*/
int GroundTrafficController::changePassword(string old_pw, string new_pw){
	//check the old password
	if (getEmployeePassword ().compare(old_pw)  == 0){
		setEmployeePassword(new_pw);
		return 1; //success
	}
	return 0; //failed
}